from os.path import exists, isfile, isdir
from os import sep, makedirs, listdir, remove
import hashlib
import cPickle as pickle
from shutil import rmtree

__doc__ = """\
ChomsPy Utility Functions

"""

def AddSep(s):
	if not s.endswith(sep):
		s += sep
	return s

def Passwd(s):
	return hashlib.sha512(s).hexdigest()
	
def checkSubjectType(subject):
	if subject["subject"].startswith("__"):
		return "admin"
	if subject["subject"].startswith("_Admin"):
		return False
	if subject["subject"].startswith("_"):
		return "private"
	else:
		return "public"

def checkPermissions(userLevel, permLevel):
	if userLevel < permLevel:
		return False
	else:
		return True

def checkSubjectFormat(subject):
	if "subject" in subject and "mods" in subject:
		if type(subject["subject"]) == type(str()) or type(subject["subject"]) == type(unicode()):
			if type(subject["mods"]) == type(list()):
				return True
			else:
				return False
		else:
			return False
	else:
		return False

def checkObjectFormat(obj):
	if "object" in obj and "mods" in obj:
		if type(obj["object"]) == type(str()) or type(obj["object"]) == type(unicode()):
			if type(obj["mods"]) == type(list()):
				return True
			else:
				return False
		else:
			return False
	else:
		return False

def checkAdminMode(subject):
	if subject["subject"] == "__Admin":
		return "global"
	else:
		return "private"

def checkDB(dbroot):
	if exists(dbroot):
		return True
	else:
		return False

def checkUserfile(dbroot, subject=False):
	if not subject:
		if exists(AddSep(dbroot) + "userfile"):
			return True
		else:
			return False
	else:
		if subject["subject"].startswith("__"):
			subject["subject"] = subject["subject"][1:]
		if exists(AddSep(dbroot) + AddSep(subject["subject"]) + "userfile"):
			return True
		else:
			return False

def getUserfile(dbroot, subject=False):
	if not subject:
		return loadObject(AddSep(dbroot), "userfile")
	else:
		if subject["subject"].startswith("__"):
			subject["subject"] = subject["subject"][1:]
		return loadObject(AddSep(dbroot) + AddSep(subject["subject"]), "userfile")

def setUserfile(dbroot, data=False, subject=False):
	if not data:
		return generateError(98, "No user data provided.", [ dbroot ])
	if not subject:
		return saveObject(AddSep(dbroot), "userfile", data)
	else:
		if subject["subject"].startswith("__"):
			subject["subject"] = subject["subject"][1:]
		return saveObject(AddSep(dbroot) + AddSep(subject["subject"]), "userfile", data)
	
def saveObject(path, f, data=False):
	if not data:
		return generateError(109, "No data to save.", [ path, f, data ])
	try:
		f = open(AddSep(path) + f, "wb")
		d = pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
		f.close()
		return data
	except OSError, e:
		return generateError(116, e.strerror, [ path, f, data ])
	except IOError, e:
		return generateError(118, e.strerror, [ path, f, data ])
	
def loadObject(path, f):
	try:
		f = open(AddSep(path) + f, "rb")
		d = pickle.load(f)
		f.close()
		return d
	except OSError, e:
		return generateError(128, e.strerror, [ path, f ])
	except IOError, e:
		return generateError(130, e.strerror, [ path, f ])

def deleteObject(path, f):
	if "*" in f:
		try:
			k = f.split("*")
			files = listdir(path)
			for i in files:
				if isfile(AddSep(path) + i):
					if i.startswith(k[0]):
						if i.endswith(k[1]):
							remove(AddSep(path) + i)
			return True
		except OSError:
			return False
		except IOError:
			return False
		
	try:
		remove(AddSep(path) + f)
		return True
	except OSError:
		return False
	except IOError:
		return False

def generateSubjectPath(dbroot, subject):
	path = AddSep(dbroot) + AddSep(subject["subject"])
	if len(subject["mods"]) > 0:
		path += AddSep(sep.join(subject["mods"]))
	return path
	
def generateObjectFilename(obj, delimiters):
	if len(obj["mods"]) == 0:
		return "_schema_" + delimiters[0] + obj["object"]
	if len(obj["mods"]) > 1:
		return delimiters[1].join(obj["mods"]) + delimiters[0] + obj["object"]
	else:
		return obj["mods"][0] + delimiters[0] + obj["object"]

def generateSchema(data):
	schema = {}
	for k in data:
		if type(data[k]) == type(str()) or type(data[k]) == type(unicode()):
			schema[k] = ""
		elif type(data[k]) == type(list()):
			schema[k] = []
		elif type(data[k]) == type(dict()):
			schema[k] = {}
		elif type(data[k]) == type(int()):
			schema[k] = 0
		elif type(data[k]) == type(float()):
			schema[k] = 0.0
		elif type(data[k]) == type(bool()):
			schema[k] = True
		else:
			return generateError(0, "Invalid data type in Data.", [ k, data ])
	return schema

def getSchema(dbroot, subject, obj, delimiters):
	r = loadObject(generateSubjectPath(dbroot, subject), generateObjectFilename(obj, delimiters))
	if "error" in r:
		return False
	else:
		return r
	
def validateObject(schema, data):
	for k in schema:
		if k in data:
			if not type(schema[k]) == type(data[k]):
				return False
		else:
			return False
	return True

def checkSubjectExists(path):
	if exists(path):
		return True
	else:
		return False
	
def createSubject(dbroot, subject, data=False):
	path = AddSep(dbroot) + AddSep(subject["subject"]) + sep.join(subject["mods"])
	try:
		makedirs(path)
		if data:
			r = saveObject(AddSep(path), "userfile", data)
			if "error" in r:
				return False
		return True
	except OSError:
		return False
	except IOError:
		return False

def createDB(dbroot, user, password):
	if user == "" or password == "":
		return False
	try:
		makedirs(dbroot)
		data = { user : { "password" : Passwd(password), "level" : 3 }}
		r = saveObject(dbroot, "userfile", data)
		if "error" in r:
			return False
		return True
	except OSError:
		return False
	except IOError:
		return False

def deleteSubject(path):
	try:
		rmtree(path)
		return True
	except OSError:
		return False
	except IOError:
		return False

def generateError(errno, msg, data):
	return { "error" : errno, "message" : msg, "data" : data }

def getSubjectList(dbroot, subject, obj=False):
	data = []
	if not obj:
		if subject["subject"] == "*":
			for i in listdir(dbroot):
				if isdir(AddSep(dbroot) + i):
					data.append(i)
			if len(data) < 1:
				data = [ "" ]
			return data
		if "*" in subject["mods"]:
			subject["mods"].remove("*")
			path = generateSubjectPath(dbroot, subject)
			for i in listdir(path):
				if isdir(AddSep(path) + i):
					data.append(i)
			return data
		else:
			return False
	else:
		if not obj["object"] == "Subject":
			return False
		if "*" in obj["mods"]:
			obj["mods"].remove("*")
			path = AddSep(dbroot) + subject["subject"] + sep.join(obj["mods"])
			for i in listdir(path):
				if isdir(AddSep(path) + i):
					data.append(i)
			return data
		else:
			return False

def getObjectList(path, obj, delimiters):
	if not checkSubjectExists(path):
		return False
	data = listdir(path)
	if obj["object"] == "*":
		for i in data:
			if not isfile(AddSep(path) + i):
				data.remove(i)
		for i in data:
			x = i.split(delimiters[0])
			if len(x) == 2:
				data[data.index(i)] = x[1] + delimiters[0] + x[0]
			else:
				data.remove(i)
	else:
		if "*" in obj["mods"]:
			obj["mods"].remove("*")
			k = delimiters[1].join(obj["mods"])
			d = []
			for i in data:
				if isfile(AddSep(path) + i):
					if i.startswith(k) and i.endswith(obj["object"]):
						d.append(i)
			for i in d:
				x = i.split(delimiters[0])
				if len(x) == 2:
					d[d.index(i)] = x[1] + delimiters[0] + x[0]
				else:
					d.remove(i)
			data = d
		else:
			return False
	return data

def validateUserData(data):
	if "password" in data and "level" in data:
		if type(data["password"]) == type(str()) or type(data["password"]) == type(unicode()):
			if type(data["level"]) == type(int()):
				return True
			else:
				return False
		else:
			return False
	else:
		return False

def generateStatus(message, data):
	return { "status" : message, "data" : data }
